package cn.changeforyou.web.cloud.devUtilApi.modules.json.service.impl;

import cn.changeforyou.utils.checker.RegExpValidatorUtils;
import cn.changeforyou.web.cloud.devUtilApi.modules.json.service.JsonService;
import cn.changeforyou.web.cloud.devUtilApi.modules.sql.impl.JavaParserUtil;
import cn.changeforyou.web.cloud.devUtilApi.modules.sql.impl.TimeType;
import cn.changeforyou.web.cloud.devUtilApi.modules.sql.impl.WriteJavaEntityContext;
import cn.changeforyou.web.cloud.devUtilApi.modules.sql.model.Common2JavaEntityModel;
import cn.changeforyou.web.cloud.devUtilApi.parser.java.JavaEntity;
import cn.changeforyou.web.cloud.devUtilApi.parser.java.JavaEntityField;
import cn.hutool.core.exceptions.NotInitedException;
import com.alibaba.fastjson2.JSON;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;

/**
 * @author zhyu
 * @version 1.0
 * @date 2022-7-31 12:20
 */
@Service
public class JsonServiceImpl implements JsonService {

    @Override
    public String json2Pojo(Common2JavaEntityModel model) {
        String value = model.getValue();

        LinkedHashMap<String, Object> jsonMap = JSON.parseObject(value, LinkedHashMap.class);
        TimeType timeType = model.getTimeType();
        String className = model.getClassName();
        int index = className.lastIndexOf(".");
        if (index == -1) {
            throw new NotInitedException("类完全限定名错误");
        }
        String packageName = className.substring(0, index);
        String javaName = className.substring(index + 1);

        JavaEntity javaEntity = new JavaEntity();
        javaEntity.setName(javaName);
        javaEntity.setPackageName(packageName);
        List<JavaEntityField> javaEntityFields = javaEntity.getJavaEntityFields();
        for (Map.Entry<String, Object> entry : jsonMap.entrySet()) {
            String k = entry.getKey();
            Object v = entry.getValue();

            Class type = judgeTypeByNameAndValue(timeType, k, v);
            JavaEntityField field = new JavaEntityField();
            javaEntityFields.add(field);

            field.setName(k);
            field.setJavaClass(type);
        }

        WriteJavaEntityContext context = new WriteJavaEntityContext();
        context.setLombok(model.isLombok());
        context.setTimeType(timeType);
        context.setSerializationType(model.getSerializationType());
        return JavaParserUtil.writeJavaEntityString(javaEntity, context);
    }

    /**
     * 根据名称或值断定类型
     *
     * @param timeType
     * @param k
     * @param v
     * @return
     */
    private static Class judgeTypeByNameAndValue(TimeType timeType, String k, Object v) {
        Class type = null;
        if (k.endsWith("id") || k.endsWith("Id")) {
            if (RegExpValidatorUtils.isNumber(String.valueOf(v))) {
                type = Long.class;
            } else {
                type = String.class;
            }
        }
        if (k.endsWith("uuid") || k.endsWith("Uuid")) {
            type = String.class;
        }

        if (k.endsWith("money") || k.endsWith("Money")) {
            type = BigDecimal.class;
        }

        if (k.endsWith("code") || k.endsWith("Code")) {
            if (RegExpValidatorUtils.isNumber(String.valueOf(v))) {
                type = Long.class;
            } else {
                type = String.class;
            }
        }

        if (k.endsWith("count") || k.endsWith("Count")) {
            if (RegExpValidatorUtils.isNumber(String.valueOf(v))) {
                type = Integer.class;
            } else {
                type = String.class;
            }
        }

        if (k.endsWith("time") || k.endsWith("Time")) {
            if (RegExpValidatorUtils.isNumber(String.valueOf(v))) {
                switch (timeType) {
                    case java8TimeApi:
                        type = LocalDateTime.class;
                        break;
                    case Date:
                        type = Date.class;
                        break;
                    case Long:
                        type = Long.class;
                        break;
                    case String:
                        type = String.class;
                        break;
                }
            } else {
                type = String.class;
            }
        }
        if (k.endsWith("date") || k.endsWith("Date")) {
            if (RegExpValidatorUtils.isNumber(String.valueOf(v))) {
                switch (timeType) {
                    case java8TimeApi:
                        type = LocalDate.class;
                        break;
                    case Date:
                        type = Date.class;
                        break;
                    case String:
                        type = String.class;
                        break;
                }
            } else {
                type = String.class;
            }
        }

        if (type == null) {
            type = String.class;
        }
        return type;
    }

    private static String[] parsePatterns = {"yyyy-MM-dd", "yyyy年MM月dd日",
            "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy/MM/dd",
            "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyyMMdd"};

    public static Date parseDate(String str) {
        if (str == null) {
            return null;
        }
        try {
            return DateUtils.parseDate(str, parsePatterns);
        } catch (ParseException e) {
            return null;
        }
    }

    public static Date parseUTCText(String text) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
        sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
        if (text.indexOf(".") > -1) {
            String prefix = text.substring(0, text.indexOf("."));
            String suffix = text.substring(text.indexOf("."));
            if (suffix.length() >= 5) {
                suffix = suffix.substring(0, 4) + "Z";
            } else {
                int len = 5 - suffix.length();
                String temp = "";
                temp += suffix.substring(0, suffix.length() - 1);
                for (int i = 0; i < len; i++) {
                    temp += "0";
                }
                suffix = temp + "Z";
            }
            text = prefix + suffix;
        } else {
            text = text.substring(0, text.length() - 1) + ".000Z";
        }
        Date date = sdf.parse(text);
        return date;
    }

}
